#pragma once

#include "Common.h"
#include "ThreadCache.h"
#include "PageCache.h"
#include "ObjectPool.h"

//并发环境下的内存分配入口函数
//大内存直接通过PageCache分配，加锁保证线程安全（因频率低，锁竞争影响小）
//小内存通过线程本地缓存ThreadCache分配,无锁高效
static void* ConcurrentAlloc(size_t size)
{
	if (size > MAX_BYTES)
	{
		size_t alignSize = SizeClass::RoundUp(size);  // 计算对齐后的内存大小
		size_t kpage = alignSize >> PAGE_SHIFT;       // 计算需要的页数

		// 访问全局PageCache，需要加锁保证线程安全
		PageCache::GetInstance()->_pageMtx.lock();
		Span* span = PageCache::GetInstance()->NewSpan(kpage);  // 申请kpage页的Span
		span->_objSize = size;  // 记录该Span分配的对象大小
		PageCache::GetInstance()->_pageMtx.unlock();

		// 计算内存块的起始地址并返回
		void* ptr = (void*)(span->_pageId << PAGE_SHIFT);
		return ptr;
	}
	else
	{
		// 通过TLS 每个线程无锁的获取自己的专属的ThreadCache对象
		if (pTLSThreadCache == nullptr)
		{
			static ObjectPool<ThreadCache> tcPool;  // ThreadCache的对象池
			//pTLSThreadCache = new ThreadCache;
			pTLSThreadCache = tcPool.New();  // 从对象池获取ThreadCache
		}

		//cout << std::this_thread::get_id() << ":"<<pTLSThreadCache<<endl;

		return pTLSThreadCache->Allocate(size);  // 从线程缓存分配内存
	}

}

//并发环境下的内存释放函数
static void ConcurrentFree(void* ptr, size_t size)
{
	//1：定位内存块所属的 Span
	Span* span = PageCache::GetInstance()->MapObjectToSpan(ptr);
	size_t size = span->_objSize;

	//2：大内存
	if (size > MAX_BYTES)
	{
		PageCache::GetInstance()->_pageMtx.lock();
		PageCache::GetInstance()->ReleaseSpanToPageCache(span);
		PageCache::GetInstance()->_pageMtx.unlock();
	}
	else//小内存
	{
		assert(pTLSThreadCache);
		pTLSThreadCache->Deallocate(ptr, size);
	}
}